import json
import logging
import re
from typing import Literal
import uuid
import falcon
import jwt
from jwcrypto import jwk, jwe
from SessionManager import SessionManager
from SessionTypeDefine import (
    JWT_ENCRPYTION_KEY,
    JWT_SECRET,
    SESSION_COOKIE_NAME,
    SSID_COOKIE_NAME,
    JWTPayload,
)
from myEncryption import chacha20_decrypt_b64, chacha20_encrypt_b64

# TODO 整理代码


class SecurityMiddleware:
    def __init__(self) -> None:
        self.sm = SessionManager()

    async def process_request(self, req: falcon.Request, resp: falcon.Response):
        if req.path != "/t2":
            # FEAT:自己完善跳过机制
            return
        logging.info("[INFO]SecurityMiddleware process request")
        # jwt没有被篡改，ssid也校验过了
        sdevice = await self.sm.get_one_key(req.context.ssid, "device")
        # 自己增加检查设备环境
        sip = await self.sm.get_one_key(req.context.ssid, "ip")
        # 自己增加检查IP地址

    async def process_resource(
        self, req: falcon.Request, resp: falcon.Response, resource, params
    ):
        logging.info("[INFO]SecurityMiddleware process resource")
        if req.content_type == "application/enc-json":
            try:
                k = req.context.redis.get("sessionAesKey")
                d: bytes = await req.bounded_stream.read()
                d: str = chacha20_decrypt_b64(
                    d.decode(), "srDWUzIWdbJC4hmo+Y7EfKX88PWspNwZ"
                )
                req.context.decoded = d
            except Exception as e:
                logging.error(e)
                # raise falcon.HTTPUnauthorized(title="JWT Error", description=str(e))

    async def process_response(
        self, req: falcon.Request, resp: falcon.Response, resource, req_succeeded
    ):
        logging.info("[INFO]SecurityMiddleware process response")
        if resp.content_type == "application/enc-json":
            k = req.context.redis.get("sessionAesKey")
            m = resp.media
            if type(m) == str:
                resp.media = None
                resp.text = json.dumps(
                    {
                        "enc-json": chacha20_encrypt_b64(
                            m, "srDWUzIWdbJC4hmo+Y7EfKX88PWspNwZ"
                        )
                    }
                )
            elif type(m) == dict:
                if d := m.get("enc-json"):
                    m["enc-json"] = chacha20_encrypt_b64(
                        d, "srDWUzIWdbJC4hmo+Y7EfKX88PWspNwZ"
                    )
                    resp.media = None
                    resp.text = json.dumps(m)
                else:
                    raise falcon.HTTPBadRequest(
                        title="Missing enc-part", description="缺少加密部分[0x0210]"
                    )
            else:
                if not type(m) == None:
                    raise falcon.HTTPBadRequest(
                        title="Unknown Type", description="无法处理的类型[0x0211]"
                    )
                else:
                    pass
        else:
            # 不处理
            pass


class SessionMiddleware:
    def __init__(self) -> None:
        self.sm = SessionManager()

    def _isByPassURL_(
        self,
        url: str,
        method: (
            str | Literal["GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"]
        ),
    ) -> bool:
        ignore_item = [
            {
                "url": r"^/$",
                "method": ["ALL"],
            },
            {
                "url": r"^/index\.html$",
                "method": ["ALL"],
            },
            {
                "url": r"^/favicon\.ico$",
                "method": ["ALL"],
            },
            {
                "url": r"^/public/",
                "method": ["ALL"],
            },
            {
                "url": r"^/login?$",
                "method": ["GET"],
            },
        ]
        for pattern in ignore_item:
            if re.match(pattern["url"], url):
                if pattern["method"] == ["ALL"]:
                    return True
                if method.upper() in pattern["method"]:
                    return True
                else:
                    return False
        return False

    async def process_request(self, req: falcon.Request, resp: falcon.Response):
        if self._isByPassURL_(req.path, req.method):
            return
        logging.info("[INFO]SessionMiddleware process request")
        if ssid := req.get_cookie_values(SSID_COOKIE_NAME):
            ssid = ssid[0]
            try:
                uuid.UUID(ssid)
                req.context.ssid = ssid
            except ValueError:
                raise falcon.HTTPUnauthorized(
                    title="Invalid SSID",
                    description="SSID格式不正常, 不符合uuid格式[0x0201]",
                )
        else:
            raise falcon.HTTPUnauthorized(
                title="No SSID found.", description="cookie ssid 不存在s[0x0203]"
            )

        if ssjwt := req.get_cookie_values(SESSION_COOKIE_NAME):
            ssjwt = ssjwt[0]
            # ssredis: dict = await self.sm.get_session_data(ssid=ssid)
            try:
                j = chacha20_decrypt_b64(ssjwt, JWT_ENCRPYTION_KEY)
                payload: JWTPayload = jwt.decode(j, JWT_SECRET, algorithms="HS256")
                if payload:
                    if payload["ssid"] == ssid:
                        # req.context.ssid = ssid 前面赋值过了
                        # req.context.redis = await self.sm.get_session_data(ssid)
                        req.context.jwt = payload
                        # req.context.redis = ssredis
                    else:
                        raise falcon.HTTPUnauthorized(
                            title="Invalid SSID",
                            description="ssid与session不匹配[0x0204]",
                        )
                else:
                    raise falcon.HTTPUnauthorized(
                        title="Invalid JWT", description="空的jwt负载[0x0205]"
                    )
            except jwt.exceptions.ExpiredSignatureError:
                raise falcon.HTTPUnauthorized(
                    title="JWT error", description="jwt过期[0x0206]"
                )
            except jwt.exceptions.DecodeError as e:
                raise falcon.HTTPUnauthorized(
                    title="jwt error", description="jwt解析错误[0x0207]"
                )
            except jwt.exceptions.PyJWTError:
                raise falcon.HTTPUnauthorized(
                    title="Invalid JWT", description="jwt其他错误[0x1C7B]"
                )
        else:
            # 可能是登陆前的访问，只有空ssid，没有session，直接跳过
            return

    async def process_resource(
        self, req: falcon.Request, resp: falcon.Response, resource, params
    ):
        logging.info("[INFO]SessionMiddleware process resource")

    async def process_response(
        self, req: falcon.Request, resp: falcon.Response, resource, req_succeeded
    ):
        logging.info("[INFO]SessionMiddleware process response")
